using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Diagnostics;
using System.Reflection;

using Softelvdm.SftTreeNET;
using Softelvdm.Controls;

namespace ExploreAssembly
{
    public partial class Form1 : Form
    {
        // This example implements dynamically populating the tree control ("load as you go").
        // As items are added, they are marked as expandable (ExpandCollapseButton = 
        // ExpandCollapseButtonStyleEnum.Show, even though no child items are added (yet).
        // Once the user clicks on the expand/collapse button, the child items are added.
        // The data displayed is created by loading an assembly and displaying defined
        // types.
        public Form1()
        {
            InitializeComponent();
        }

        const BindingFlags bFlags = BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;

        private void CloseButton_Click(object sender, EventArgs e) {
            Close();
        }

        private void LoadButton_Click(object sender, EventArgs e) {
            openFileDialog1.ShowDialog();
        }
        private void openFileDialog1_FileOk(object sender, CancelEventArgs e) {
            LoadAssembly(openFileDialog1.FileName);
        }

        private void LoadAssembly(Assembly asm) {
            sftTree1.Initializing = true;

            ItemCollectionClass itemCollection = sftTree1.ItemCollection;
            itemCollection.Clear();

            ListInfo(itemCollection, asm);
            itemCollection.Sort();

            sftTree1.Headers[0, 0].Text = asm.FullName;

            sftTree1.Columns.MakeOptimal(0, true);
            sftTree1.RecalcHorizontalExtent();
            sftTree1.Initializing = false;
        }

        private void LoadAssembly(string newInputFile)
        {
            Assembly asm = null;
            try {
                asm = Assembly.LoadFrom(newInputFile);

            } catch (Exception e) {
                MessageBox.Show(e.Message);
                return;
            }
            LoadAssembly(asm);
        }

        private void ListInfo(ItemCollectionClass itemCollection, Assembly a) {
            ItemClass item = itemCollection.Add("Custom Attributes");
            item.TagObjects = a.GetCustomAttributes(true);
            item.ExpandCollapseButton = item.TagObjects.Length > 0 ? ExpandCollapseButtonStyleEnum.Show : ExpandCollapseButtonStyleEnum.Hide;

            item = itemCollection.Add("Exported Types");
            item.TagObjects = a.GetExportedTypes();
            item.ExpandCollapseButton = item.TagObjects.Length > 0 ? ExpandCollapseButtonStyleEnum.Show : ExpandCollapseButtonStyleEnum.Hide;

            item = itemCollection.Add("Files");
            item.TagObjects = a.GetFiles();
            item.ExpandCollapseButton = item.TagObjects.Length > 0 ? ExpandCollapseButtonStyleEnum.Show : ExpandCollapseButtonStyleEnum.Hide;

            item = itemCollection.Add("Manifest Resource Names ");
            item.TagObjects = a.GetManifestResourceNames();
            item.ExpandCollapseButton = item.TagObjects.Length > 0 ? ExpandCollapseButtonStyleEnum.Show : ExpandCollapseButtonStyleEnum.Hide;

            item = itemCollection.Add("Properties");
            PropertyInfo[] props = typeof(Assembly).GetProperties(bFlags);
            foreach (PropertyInfo p in props) {
                string sval = "";
                try {
                    object val = p.GetValue(a, null);
                    if (val != null)
                        sval = val.ToString();
                    else 
                        sval = "(null)";
                } catch {
                    sval = "(?)";
                }
                item.Add(new string[] { p.Name, sval });
            }
            item.Children.Sort();
        }

        private void ListInfo(ItemCollectionClass itemCollection, object o) {

            Type tp = o.GetType();

            ItemClass  item = itemCollection.Add("Custom Attributes");
            item.TagObjects = tp.GetCustomAttributes(true);
            item.ExpandCollapseButton = ExpandCollapseButtonStyleEnum.Show;

            item = itemCollection.Add("Events");
            item.TagObjects = tp.GetEvents(bFlags);
            item.ExpandCollapseButton = item.TagObjects.Length > 0 ? ExpandCollapseButtonStyleEnum.Show : ExpandCollapseButtonStyleEnum.Hide;

            item = itemCollection.Add("Fields");
            item.TagObjects = tp.GetFields(bFlags);
            item.ExpandCollapseButton = item.TagObjects.Length > 0 ? ExpandCollapseButtonStyleEnum.Show : ExpandCollapseButtonStyleEnum.Hide;

            item = itemCollection.Add("Interfaces");
            item.TagObjects = tp.GetInterfaces();
            item.ExpandCollapseButton = item.TagObjects.Length > 0 ? ExpandCollapseButtonStyleEnum.Show : ExpandCollapseButtonStyleEnum.Hide;

            item = itemCollection.Add("Members");
            item.TagObjects = tp.GetMembers(bFlags);
            item.ExpandCollapseButton = item.TagObjects.Length > 0 ? ExpandCollapseButtonStyleEnum.Show : ExpandCollapseButtonStyleEnum.Hide;

            item = itemCollection.Add("Methods");
            item.TagObjects = tp.GetMethods(bFlags);
            item.ExpandCollapseButton = item.TagObjects.Length > 0 ? ExpandCollapseButtonStyleEnum.Show : ExpandCollapseButtonStyleEnum.Hide;

            item = itemCollection.Add("Nested Types");
            item.TagObjects = tp.GetNestedTypes(bFlags);
            item.ExpandCollapseButton = item.TagObjects.Length > 0 ? ExpandCollapseButtonStyleEnum.Show : ExpandCollapseButtonStyleEnum.Hide;

            item = itemCollection.Add("Properties");
            PropertyInfo[] props = tp.GetProperties(bFlags);
            foreach (PropertyInfo p in props) {
                string sval = "";
                try {
                    object val = p.GetValue(o, null);
                    if (val != null)
                        sval = val.ToString();
                    else 
                        sval = "(null)";
                } catch {
                    sval = "(?)";
                }
                item.Add(new string[] { p.Name, sval });
            }
            item.Children.Sort();
        }

        private void Form1_Load(object sender, EventArgs e) {
            sftTree1.Columns.Count = 2;
            sftTree1.Headers.Reorderable = sftTree1.Footers.Reorderable = false;
            sftTree1.Headers.MergeWithNextDefault = true;
            sftTree1.Headers.AllowMergeFromPreviousDefault = true;
            sftTree1.Columns[0].MergeWithNextDefault = true;
            sftTree1.Columns[1].AllowMergeFromPreviousDefault = true;
            sftTree1.MergeStyle = MergeStyleEnum.EmptyCells;
            sftTree1.AutoRespond = false;
            sftTree1.RowHeaders.Width = 0;
            LoadAssembly(Assembly.GetExecutingAssembly());
        }

        private void ExpandCollapseItem(ItemClass item)
        {
            if (item.Expanded)
                item.Collapse(CollapseStyleEnum.SaveCurrent);
            else {
                if (item.HasChildren)
                    item.Expand(ExpandStyleEnum.RestoreLast);
                else {
                    sftTree1.Initializing = true;
                    if (item.TagString == "Single") {
                        item._CreateChildren = true;
                        ListInfo(item.Children, item.TagObject);
                    } else {
                        foreach (object o in item.TagObjects) {
                            ItemClass newItem = item.Add(o.ToString());
                            newItem.TagObject = o;
                            newItem.ExpandCollapseButton = ExpandCollapseButtonStyleEnum.Show;
                            newItem.TagString = "Single";
                        }
                    }
                    item.Children.Sort();
                    item.ExpandCollapseButton = ExpandCollapseButtonStyleEnum.Conditional;
                    item.Expand(ExpandStyleEnum.DirectOnly);
                    sftTree1.Initializing = false;
                }
            }
            sftTree1.Columns.MakeOptimal(0, true);
            sftTree1.RecalcHorizontalExtent();
        }

        private void sftTree1_ItemClick(object sender, ItemClickEventArgs e) {
            Debug.Write("ItemClick ");
            DumpValues(e);
            // user clicks expand/collapse button
            if (e.Area == ItemClickAreaEnum.ExpandCollapseButton && e.Item != null) {
                ExpandCollapseItem(e.Item);
            }
        }
        private void sftTree1_ItemDoubleClick(object sender, ItemClickEventArgs e) {
            Debug.Write("ItemDoubleClick ");
            DumpValues(e);
            // user double clicks on an item
            if (e.Area == ItemClickAreaEnum.CellSel && e.Item != null) {
                ExpandCollapseItem(e.Item);
            }
        }
        private void sftTree1_KeyDown(object sender, KeyEventArgs e) {
            if (e.KeyCode == Keys.Right) {
                // Right arrow normally expands a parent item. Our items don't (yet) have 
                // child items, so we'll have to handle the right arrow keys. 
                ItemClass item = sftTree1.FocusItem;
                if (item != null) {
                    if (item.ExpandCollapseButton == ExpandCollapseButtonStyleEnum.Show) {
                        ExpandCollapseItem(item);
                        e.Handled = true;
                    }
                }
            }
        }
        // This is a small helper routine to show all properties and fields of an object
        private void DumpValues(object o) {
            PropertyInfo[] api = o.GetType().GetProperties();
            foreach (PropertyInfo pi in api)
                Debug.Write(" " + pi.Name + " " + pi.GetValue(o, new object[] { }));
            FieldInfo[] afi = o.GetType().GetFields();
            foreach (FieldInfo fi in afi)
                Debug.Write(" " + fi.Name + " " + fi.GetValue(o));
            Debug.WriteLine("");
        }
    }
}